import { useCallback, useEffect, useRef } from 'react';
import { Form, FormInstance, TablePaginationConfig } from 'antd';
import { isEmpty, isPlainObject } from 'lodash';
import { FilterValue, SorterResult, TableCurrentDataSource } from 'antd/lib/table/interface';
import { useMeModel } from './model';

type Model<T> = {
  loading: boolean;
  values: {
    current?: number;
    pageSize?: number;
    [key: string]: any;
  };
  dataSource: {
    data: T[];
    current: number;
    pageSize: number;
    total: number;
  };
};

const model = {
  loading: false,
  values: {
    current: 1,
    pageSize: 10,
  },
  dataSource: {
    current: 1,
    pageSize: 10,
    total: 0,
    data: [],
  },
};

type TableOptions = {
  autoLoad?: boolean;
  params?: Record<string, any>;
  currentField?: string;
  pageSizeField?: string;
  memoKey?: string;
  query: (params?: any) => Promise<any>;
  transform?: (resp: any) => any;
};

/**
 * 简单的表格查询功能
 * @param options
 * @returns
 */
export const useTableAction = <T>(options: TableOptions) => {
  const {
    autoLoad = true,
    currentField = 'current',
    pageSizeField = 'pageSize',
    params,
    memoKey,
    query,
    transform,
  } = options;
  const { state, put, get } = useMeModel<Model<T>>(
    () => ({
      ...model,
      values: {
        [currentField]: model.values.current,
        [pageSizeField]: model.values.pageSize,
        ...params,
      },
    }),
    memoKey
  );

  const unmountedRef = useRef(false);

  const promiseRef = useRef<Promise<any> | undefined>();

  const pageServerRef = useRef(true);

  const queryTableList = async () => {
    if (unmountedRef.current) {
      return;
    }
    put({ loading: true });
    const { values } = await get();
    const promis = query(values);
    promiseRef.current = promis;
    try {
      const resp = await promis;
      if (promiseRef.current !== promis) {
        return;
      }
      if (Array.isArray(resp?.data)) {
        // 非服务端分页
        pageServerRef.current = false;
      }
      const dataSource = transform ? transform(resp) : parseResToDataSource(resp?.data);
      // 判断当前页数据， 不存在时，请求上一页
      if (!dataSource.data.length && values[currentField] > 1) {
        put({
          values: { ...values, [currentField]: values[currentField] - 1 },
        });
        queryTableList();

        return;
      }
      put({
        dataSource,
        loading: false,
      });
    } catch (error) {
      if (promiseRef.current !== promis) {
        return;
      }
      put({ loading: false, dataSource: model.dataSource });
    }
  };

  // 表单查询
  const onTableSearch = useCallback((values: Record<string, any>, reset = false) => {
    put(st => ({
      ...st,
      values: {
        ...st.values,
        ...values,
        [currentField]: 1,
      },
    }));

    !reset && queryTableList();
  }, []);

  const onPaginationChange = (current: number, pageSize = 10) => {
    put(st => ({
      values: {
        ...st.values,
        [currentField]: current,
        [pageSizeField]: pageSize,
      },
    }));
    if (pageServerRef.current) {
      // 服务端分页
      queryTableList();
    } else {
      // 前端分页
      put(st => ({
        dataSource: {
          ...st.dataSource,
          current,
          pageSize,
        },
      }));
    }
  };

  // 表格change
  const onTableChange = useCallback(
    (
      pageOption: TablePaginationConfig,
      filters: Record<string, FilterValue | null>,
      sorter: SorterResult<any> | SorterResult<any>[],
      extra: TableCurrentDataSource<any>
    ) => {
      const { action } = extra;
      switch (action) {
        case 'filter': {
          // 暂未实现
          break;
        }
        case 'sort': {
          const sortBy = getSortParams(sorter);
          if (sortBy) {
            put(st => ({
              values: {
                ...st.values,
                sortBy,
                current: 1,
              },
            }));
            queryTableList();
          }
          break;
        }
        case 'paginate': {
          const { current = 1, pageSize = 10 } = pageOption;
          onPaginationChange(current, pageSize);
          break;
        }
        default:
      }
    },
    []
  );

  useEffect(() => {
    unmountedRef.current = false;

    if (autoLoad) {
      queryTableList();
    }

    return () => {
      unmountedRef.current = true;
      promiseRef.current = undefined;
    };
  }, []);

  return {
    state,
    put,
    get,
    queryTableList,
    onTableSearch,
    onTableChange,
  };
};

const getSortParams = (sorter: SorterResult<any> | SorterResult<any>[]) => {
  if (Array.isArray(sorter)) {
    if (!sorter.length) {
      return null;
    }
    const result = {};
    sorter.forEach(s => {
      const obj = getColSortParams(s);

      if (obj) {
        Object.assign(result, obj);
      }
    });

    return isEmpty(result) ? null : result;
  }

  return getColSortParams(sorter);
};

const getColSortParams = (sorter: SorterResult<any>) => {
  if (!sorter) {
    return null;
  }
  const { field, order } = sorter;
  const column: any = sorter?.column;

  if (column?.sorter === true || !column?.sorter?.compare) {
    if (!field) {
      return null;
    }

    return {
      [field.toString()]: order,
    };
  }

  return null;
};

type TableProOptions = {
  autoLoad?: boolean;
  params?: Record<string, any>;
  currentField?: string;
  pageSizeField?: string;
  memoKey?: string;
  service: {
    query: (params: any) => Promise<any>;
    add?: (params: any, dataSource: Model<any>['dataSource']) => Promise<any>;
    update?: (params: any, dataSource: Model<any>['dataSource']) => Promise<any>;
    del?: (params: any, dataSource: Model<any>['dataSource']) => Promise<any>;
  };
  transform?: (resp: any) => any;
};

/**
 * 表格CRUD
 * @param options
 * @returns
 */
export const useTableProAction = <T>(options: TableProOptions) => {
  const {
    autoLoad,
    params,
    memoKey,
    currentField,
    pageSizeField,
    service: {
      query, add, update, del
    },
    transform,
  } = options;

  const {
    state, put, get, queryTableList, onTableSearch, onTableChange
  } = useTableAction<T>({
    autoLoad,
    params,
    memoKey,
    currentField,
    pageSizeField,
    query,
    transform,
  });

  const onRowAdd = async (value: any) => {
    if (!add) {
      return Promise.reject(new Error('没有此方法'));
    }
    try {
      put({ loading: true });
      const { dataSource } = await get();
      await add(value, dataSource);
      put({ loading: false });
      await queryTableList();

      return Promise.resolve();
    } catch (error: any) {
      put({ loading: false });

      return Promise.reject(new Error(error));
    }
  };

  const onRowUpdate = async (value: any) => {
    if (!update) {
      return Promise.reject(new Error('没有此方法'));
    }
    try {
      put({ loading: true });
      const { dataSource } = await get();
      await update(value, dataSource);
      put({ loading: false });
      await queryTableList();

      return Promise.resolve();
    } catch (error: any) {
      put({ loading: false });

      return Promise.reject(new Error(error));
    }
  };

  const onRowDel = async (value: any) => {
    if (!del) {
      return Promise.reject(new Error('没有此方法'));
    }
    try {
      put({ loading: true });
      const { dataSource } = await get();
      await del(value, dataSource);
      put({ loading: false });
      await queryTableList();

      return Promise.resolve();
    } catch (error: any) {
      put({ loading: false });

      return Promise.reject(new Error(error));
    }
  };

  return {
    state,
    put,
    get,
    onRowAdd,
    onRowUpdate,
    onRowDel,
    onTableSearch,
    queryTableList,
    onTableChange,
  };
};

/**
 * 表单表格扩展
 * @param options
 * @returns
 */
export const useTableFormAction = <T>(
  options: TableProOptions & {
    form?: FormInstance;
  }
) => {
  const {
    autoLoad, currentField, pageSizeField, params, memoKey, service, transform
  } = options;

  const {
    state,
    put,
    get,
    onRowAdd,
    onRowUpdate,
    onRowDel,
    queryTableList,
    onTableSearch,
    onTableChange,
  } = useTableProAction<T>({
    autoLoad,
    params,
    memoKey,
    currentField,
    pageSizeField,
    service,
    transform,
  });

  const [form] = Form.useForm(options.form);

  const onReset = useCallback(() => {
    form.resetFields();
    // 重置后重新取表单值，这个有一定的延迟，具体情况请看源码
    window.requestAnimationFrame(() => {
      onSearch();
    });
  }, []);

  const formSearch = async () => {
    const values = await form.validateFields();
    onTableSearch(values);
  };

  const onSearch = useCallback((value?: Record<string, any>) => {
    if (value) {
      // 跳过事件处理
      if (value instanceof Event || value.nativeEvent instanceof Event || !isPlainObject(value)) {
        formSearch();

        return;
      }

      onTableSearch(value);

      return;
    }
    formSearch();
  }, []);

  return {
    state,
    form,
    put,
    get,
    onReset,
    onSearch,
    onRowAdd,
    onRowUpdate,
    onRowDel,
    queryTableList,
    onTableChange,
  };
};

// 表格值解析
export const parseResToDataSource = (
  result: any
): {
  data: any[];
  current: number;
  pageSize: number;
  total: number;
} => {
  if (!result) {
    return {
      data: [],
      current: 0,
      pageSize: 0,
      total: 0,
    };
  }
  if (Array.isArray(result)) {
    return {
      data: result,
      current: 1,
      pageSize: 10,
      total: result.length,
    };
  }

  const data = result.records || result.data;

  return {
    current: +result.current || 1,
    pageSize: +result.pageSize || +result.size || 10,
    total: +result.total || data?.length,
    data,
  };
};
